package com.lc.projects.unit.thread.part07.test1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class Test9 {
	public static void main(String[] args) {
		MyLock lock = new MyLock();
		for (int i = 0; i < 10; i++) {
			Task9 task = new Task9(lock, "Task"+i);
			Thread thread = new Thread(task);
			thread.start();
		}
		boolean value;
		do{
			try {
				value = lock.tryLock(1,TimeUnit.SECONDS);
				if(!value){
					System.out.println("Main:Trying to get the lock.");
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
				value = false;
			}
	
		}while(!value);
		
		System.out.println("Main: Got the lock.");
		lock.unlock();
		System.out.println("Main:End");
		
	}
}

class MyAbstractQueuedSynchronizer extends AbstractQueuedSynchronizer{
	private static final long serialVersionUID = 1L;
	private AtomicInteger state;
	
	public MyAbstractQueuedSynchronizer() {
		state = new AtomicInteger(0);
	}

	@Override
	protected boolean tryAcquire(int arg) {
		return state.compareAndSet(0, 1);
	}

	@Override
	protected boolean tryRelease(int arg) {
		return state.compareAndSet(1, 0);
	}
}

class MyLock implements Lock{
	private AbstractQueuedSynchronizer sync;
	
	public MyLock() {
		sync = new MyAbstractQueuedSynchronizer();
	}

	@Override
	public void lock() {
		sync.acquire(1);
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
	}

	@Override
	public boolean tryLock() {
		try {
			return sync.tryAcquireNanos(1, 1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
			return false;
		}
	}

	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireNanos(1, TimeUnit.NANOSECONDS.convert(time, unit));
	}

	@Override
	public void unlock() {
		sync.release(1);
	}

	@Override
	public Condition newCondition() {
		return sync.new ConditionObject();
	}
	
}


class Task9 implements Runnable{
	private MyLock lock;
	private String name;
	
	public Task9(MyLock lock, String name) {
		super();
		this.lock = lock;
		this.name = name;
	}

	@Override
	public void run() {
		lock.lock();
		System.out.println("Task: take the lock."+name);
		try {
			TimeUnit.MILLISECONDS.sleep(1000);
			System.out.println("Task: FREE the lock."+name);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
}